{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-02-09T08:22:14.544383Z",
     "start_time": "2025-02-09T08:22:12.139361Z"
    }
   },
   "source": [
    "# 导入库\n",
    "import matplotlib as mpl\n",
    "# Matplotlib 绘制的图形会直接嵌入到 Notebook 的输出单元格中，而不是弹出一个独立的窗口\n",
    "%matplotlib inline\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "\n",
    "# os库提供了一种使用操作系统相关功能的便捷方式，允许与操作系统进行交互\n",
    "import os\n",
    "\n",
    "# sys库主要用于处理Python运行时的环境相关信息以及与解释器的交互\n",
    "import sys\n",
    "import time\n",
    "\n",
    "# tqdm库是一个快速，可扩展的Python进度条，可以在 Python 长循环中添加一个进度提示信息，用户只需要封装任意的迭代器 tqdm(iterator)，即可获得一个进度条显示迭代进度。\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "\n",
    "# torch.nn是PyTorch中用于构建神经网络的模块\n",
    "import torch.nn as nn\n",
    "\n",
    "# torch.nn.functional是PyTorch中包含了神经网络的一些常用函数\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# Python 中的一个属性，用于获取当前 Python 解释器的版本信息。它返回一个命名元组（named tuple）\n",
    "print(sys.version_info)\n",
    "\n",
    "# 遍历模块，打印模块名称和版本信息，快速检查当前环境中安装的某些常用 Python 库的版本信息\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "# 判断是否有 GPU，如果有，则使用 GPU 进行训练，否则使用 CPU 进行训练\n",
    "# torch.cuda.is_available()用于判断是否有GPU\n",
    "# torch.device(\"cuda:0\")创建一个 PyTorch 设备对象，表示使用第一个 GPU（索引为 0）\n",
    "# torch.device(\"cpu\")创建一个 PyTorch 设备对象，表示使用 CPU\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.3.1+cu121\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 数据准备",
   "id": "3a42beeca3eb3091"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T08:27:33.899309Z",
     "start_time": "2025-02-09T08:27:33.491397Z"
    }
   },
   "cell_type": "code",
   "source": "!tree archive ",
   "id": "5c330b9dab8ea81f",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "卷 新加卷 的文件夹 PATH 列表\n",
      "卷序列号为 BC85-E93A\n",
      "E:\\PROJECT\\PYTHON2025\\2025-PYTHON\\DAY23\\ARCHIVE\n",
      "├─training\n",
      "│  └─training\n",
      "│      ├─n0\n",
      "│      ├─n1\n",
      "│      ├─n2\n",
      "│      ├─n3\n",
      "│      ├─n4\n",
      "│      ├─n5\n",
      "│      ├─n6\n",
      "│      ├─n7\n",
      "│      ├─n8\n",
      "│      └─n9\n",
      "└─validation\n",
      "    └─validation\n",
      "        ├─n0\n",
      "        ├─n1\n",
      "        ├─n2\n",
      "        ├─n3\n",
      "        ├─n4\n",
      "        ├─n5\n",
      "        ├─n6\n",
      "        ├─n7\n",
      "        ├─n8\n",
      "        └─n9\n"
     ]
    }
   ],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T08:56:15.079804Z",
     "start_time": "2025-02-09T08:56:15.069221Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 导入所需的库：\n",
    "# datasets: PyTorch 提供的数据集工具。\n",
    "# ToTensor, Resize, Compose, ConvertImageDtype, Normalize: 图像预处理工具。\n",
    "# Path: 用于处理文件路径。\n",
    "from torchvision import datasets\n",
    "from torchvision.transforms import ToTensor, Resize, Compose, ConvertImageDtype, Normalize\n",
    "from pathlib import Path\n",
    "\n",
    "# 定义数据集的根目录为 ./archive/\n",
    "# 使用 Path 对象处理文件路径\n",
    "DATA_DIR = Path(\"./archive/\")\n",
    "\n",
    "\n",
    "# 定义一个名为 MonkeyDataset 的类，继承自 datasets.ImageFolder\n",
    "# ImageFolder 是 PyTorch 提供的用于加载图像文件夹数据集的类\n",
    "# 该类会将图像文件路径及标签组合成样本，并将样本组合成数据集\n",
    "# 该类会自动将图像文件转换为张量，并对张量进行预处理（如缩放、归一化等）\n",
    "class MonkeyDataset(datasets.ImageFolder):\n",
    "\n",
    "    #  定义类的构造函数，接受以下参数：\n",
    "    #  mode: 数据集模式（\"train\" 或 \"val\"）。\n",
    "    #  transform: 图像预处理操作，默认值为 None\n",
    "    # 初始化数据集类，根据模式选择数据子集\n",
    "    def __init__(self, mode, transform=None):\n",
    "\n",
    "        # 根据 mode 参数选择数据子集的根目录。\n",
    "        # 如果 mode 为 \"train\"，则使用 training 子目录。\n",
    "        # 如果 mode 为 \"val\"，则使用 validation 子目录。\n",
    "        # 否则，抛出错误。\n",
    "        # 原理: 使用 Path 对象拼接路径。\n",
    "        if mode == \"train\":\n",
    "            root = DATA_DIR / \"training\" / \"training\"\n",
    "        elif mode == \"val\":\n",
    "            root = DATA_DIR / \"validation\" / \"validation\"\n",
    "        else:\n",
    "            raise ValueError(\"mode should be one of the following: train, val, but got {}\".format(mode))\n",
    "\n",
    "        # 调用父类 ImageFolder 的构造函数，传入根目录和预处理操作\n",
    "        # 父类 ImageFolder 会自动加载图像数据并应用预处理操作\n",
    "        super().__init__(root, transform)\n",
    "\n",
    "        # 将数据集的标签（目标值）存储在 self.targets 中\n",
    "        # self.samples 是 ImageFolder 中存储的样本列表，每个样本是一个元组 (图像路径, 标签)\n",
    "        # 方便后续访问数据集的标签\n",
    "        self.targets = [s[1] for s in self.samples]\n",
    "\n",
    "\n",
    "# 定义图像预处理操作，包括：\n",
    "# Resize((img_h, img_w)): 将图像调整为 224x224 大小。\n",
    "# ToTensor(): 将图像转换为 PyTorch 张量。\n",
    "# Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]): 对图像进行归一化，使用 ImageNet 的均值和标准差。\n",
    "# ConvertImageDtype(torch.float): 将张量转换为 float 类型。\n",
    "# 原理: 使用 Compose 将多个预处理操作组合在一起。\n",
    "img_h, img_w = 224, 224\n",
    "transform = Compose([\n",
    "    Resize((img_h, img_w)),\n",
    "    ToTensor(),\n",
    "    Normalize([0.4363, 0.4328, 0.3291], [0.2129, 0.2075, 0.2037]),\n",
    "    ConvertImageDtype(torch.float),\n",
    "])\n",
    "\n",
    "# 创建训练集和验证集的实例\n",
    "# 使用 MonkeyDataset 类加载数据，并应用预处理操作\n",
    "train_ds = MonkeyDataset(\"train\", transform=transform)\n",
    "val_ds = MonkeyDataset(\"val\", transform=transform)\n",
    "\n",
    "# 打印训练集和验证集的样本数量\n",
    "print(\"load {} images from training dataset\".format(len(train_ds)))\n",
    "print(\"load {} images from validation dataset\".format(len(val_ds)))"
   ],
   "id": "faaa799cb23a2285",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "load 1097 images from training dataset\n",
      "load 272 images from validation dataset\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['n0', 'n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7', 'n8', 'n9']"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 19,
   "source": [
    "# 数据类别\n",
    "train_ds.classes"
   ],
   "id": "36266a513065123f"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'n0': 0,\n",
       " 'n1': 1,\n",
       " 'n2': 2,\n",
       " 'n3': 3,\n",
       " 'n4': 4,\n",
       " 'n5': 5,\n",
       " 'n6': 6,\n",
       " 'n7': 7,\n",
       " 'n8': 8,\n",
       " 'n9': 9}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 20,
   "source": "train_ds.class_to_idx",
   "id": "547200dbf79008f7"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "archive\\training\\training\\n0\\n0018.jpg 0\n",
      "archive\\training\\training\\n0\\n0019.jpg 0\n",
      "archive\\training\\training\\n0\\n0020.jpg 0\n",
      "archive\\training\\training\\n0\\n0021.jpg 0\n",
      "archive\\training\\training\\n0\\n0022.jpg 0\n",
      "archive\\training\\training\\n0\\n0023.jpg 0\n",
      "archive\\training\\training\\n0\\n0024.jpg 0\n",
      "archive\\training\\training\\n0\\n0025.jpg 0\n",
      "archive\\training\\training\\n0\\n0026.jpg 0\n",
      "archive\\training\\training\\n0\\n0027.jpg 0\n"
     ]
    }
   ],
   "execution_count": 21,
   "source": [
    "# # 图片路径 及 标签\n",
    "i = 0\n",
    "for fpath, label in train_ds.samples:\n",
    "    print(fpath, label)\n",
    "    i += 1\n",
    "    if i == 10:\n",
    "        break"
   ],
   "id": "739b726c0858a117"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T08:55:47.496718Z",
     "start_time": "2025-02-09T08:55:29.839736Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#因为有3通道，所有有3个mean和std\n",
    "def cal_mean_std(ds):\n",
    "    mean = 0.\n",
    "    std = 0.\n",
    "    for img, _ in ds:\n",
    "        mean += img[:, :, :].mean(dim=(1, 2))\n",
    "        std += img[:, :, :].std(dim=(1, 2))\n",
    "    mean /= len(ds)\n",
    "    std /= len(ds)\n",
    "    return mean, std\n",
    "\n",
    "\n",
    "# 经过 normalize 后 均值为0，方差为1\n",
    "print(cal_mean_std(train_ds))"
   ],
   "id": "a8ee1460b46dc253",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(tensor([0.4363, 0.4328, 0.3291]), tensor([0.2129, 0.2075, 0.2037]))\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:02:48.996186Z",
     "start_time": "2025-02-09T09:02:48.991741Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import torch.nn as nn\n",
    "from torch.utils.data.dataloader import DataLoader\n",
    "\n",
    "batch_size = 64\n",
    "# 从数据集到dataloader，num_workers参数不能加，否则会报错\n",
    "# https://github.com/pytorch/pytorch/issues/59438\n",
    "train_loader = DataLoader(train_ds, batch_size=batch_size, shuffle=True)\n",
    "val_loader = DataLoader(val_ds, batch_size=batch_size, shuffle=False)"
   ],
   "id": "a8d47eb403cee9bf",
   "outputs": [],
   "execution_count": 26
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 模型定义",
   "id": "1de3a47fa81d7dd2"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:51.271068Z",
     "start_time": "2025-02-09T09:17:51.214843Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 定义一个名为 CNN 的类，继承自 nn.Module\n",
    "class CNN(nn.Module):\n",
    "\n",
    "    # 定义类的构造函数，接受一个参数 activation，表示激活函数的类型，默认值为 \"relu\"\n",
    "    # 初始化模型的层结构和参数\n",
    "    def __init__(self, num_classes=10, activation=\"relu\"):\n",
    "        super().__init__()\n",
    "\n",
    "        # 根据 activation 参数选择激活函数，F.relu 或 F.selu\n",
    "        self.activation = F.relu if activation == \"relu\" else F.selu\n",
    "\n",
    "        # 定义两个卷积层，输入通道数分别为 1 和 32，输出通道数均为 32，卷积核大小为 3x3，填充为 1。\n",
    "        # 卷积层用于提取图像的局部特征,通过卷积操作提取图像的底层特征\n",
    "        # 提取输入图像的初级特征，输出通道数增加到 32\n",
    "        # 输入：(batch_size, 1, 224,224)，输出：(batch_size, 32, 224,224)\n",
    "        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=0)\n",
    "        # 输入：(batch_size, 32, 224,224)，输出：(batch_size, 32, 224,224)\n",
    "        # 进一步提取特征，通道数保持不变\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=0)\n",
    "\n",
    "        # 定义一个最大池化层，池化核大小为 2x2，步幅为 2\n",
    "        # 池化层用于降低特征图的空间维度，减少计算量\n",
    "        # 通过池化操作减少特征图的尺寸，同时保留重要特征\n",
    "        # 输入：(batch_size, 32, 224,224)，输出：(batch_size, 32,112,112)\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "\n",
    "        # 定义两个卷积层，输入通道数分别为 32 和 64，输出通道数均为 64，卷积核大小为 3x3，填充为 1。\n",
    "        # 卷积层用于提取图像的局部特征,通过卷积操作提取图像的中层特征\n",
    "        # 输入：(batch_size, 32, 112,112)，输出：(batch_size, 64, 112,112)\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=0)\n",
    "        # 输入：(batch_size, 64, 112,112)，输出：(batch_size, 64, 112,112)\n",
    "        self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=0)\n",
    "\n",
    "        # 输入：(batch_size, 64, 112,112)，输出：(batch_size, 64, 56,56)\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "\n",
    "        # 定义两个卷积层，输入通道数分别为 64 和 128，输出通道数均为 128，卷积核大小为 3x3，填充为 1。\n",
    "        # 卷积层用于提取图像的局部特征,通过卷积操作提取图像的高层特征\n",
    "        # 输入：(batch_size, 64, 56,56)，输出：(batch_size, 128, 56,56)\n",
    "        self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=0)\n",
    "        # 输入：(batch_size, 128, 56,56)，输出：(batch_size, 128, 56,56)\n",
    "        self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=0)\n",
    "\n",
    "        # 输入：(batch_size, 128, 28,28)，输出：(batch_size, 128, 28,28)\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "\n",
    "        # 定义一个展平层，用于将多维特征图展平为一维向量\n",
    "        self.flatten = nn.Flatten()\n",
    "\n",
    "        # 定义一个全连接层，输入维度为 128 * 28 * 28，输出维度为 128。\n",
    "        # 全连接层用于将提取的特征映射到高维空间\n",
    "        self.fc1 = nn.Linear(128 * 24 * 24, 128)\n",
    "\n",
    "        # 输出层将特征映射到最终的类别数\n",
    "        self.fc2 = nn.Linear(128, num_classes)\n",
    "\n",
    "        # 调用 init_weights 方法初始化模型参数\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    #  定义前向传播方法，接受输入数据 x，并获取激活函数 act\n",
    "    def forward(self, x):\n",
    "        act = self.activation\n",
    "\n",
    "        # 将输入数据 x 依次通过 conv1、激活函数、conv2、激活函数和池化层\n",
    "        # 提取图像的底层特征，并通过池化层降低特征图的尺寸。减少计算量。\n",
    "        x = self.pool(act(self.conv2(act(self.conv1(x)))))\n",
    "\n",
    "        # 将降低尺寸后的特征图依次通过 conv3、激活函数、conv4、激活函数和池化层\n",
    "        # 提取图像的中层特征，并通过池化层降低特征图的尺寸。减少计算量。\n",
    "        x = self.pool(act(self.conv4(act(self.conv3(x)))))\n",
    "\n",
    "        # 将降低尺寸后的特征图依次通过 conv5、激活函数、conv6、激活函数和池化层\n",
    "        # 提取图像的高层特征，并通过池化层降低特征图的尺寸。减少计算量。\n",
    "        x = self.pool(act(self.conv6(act(self.conv5(x)))))\n",
    "\n",
    "        # 将降低尺寸后的特征图展平为一维向量，输入全连接层\n",
    "        x = self.flatten(x)\n",
    "\n",
    "        # 将展平后的特征向量通过全连接层 fc1 和激活函数。\n",
    "        x = act(self.fc1(x))\n",
    "\n",
    "        # 将特征向量通过全连接层 fc2，得到最终的输出\n",
    "        x = self.fc2(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "for idx, (key, value) in enumerate(CNN().named_parameters()):\n",
    "    print(f\"{key}\\tparamerters num: {np.prod(value.shape)}\")"
   ],
   "id": "1351d556e3775428",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1.weight\tparamerters num: 864\n",
      "conv1.bias\tparamerters num: 32\n",
      "conv2.weight\tparamerters num: 9216\n",
      "conv2.bias\tparamerters num: 32\n",
      "conv3.weight\tparamerters num: 18432\n",
      "conv3.bias\tparamerters num: 64\n",
      "conv4.weight\tparamerters num: 36864\n",
      "conv4.bias\tparamerters num: 64\n",
      "conv5.weight\tparamerters num: 73728\n",
      "conv5.bias\tparamerters num: 128\n",
      "conv6.weight\tparamerters num: 147456\n",
      "conv6.bias\tparamerters num: 128\n",
      "fc1.weight\tparamerters num: 9437184\n",
      "fc1.bias\tparamerters num: 128\n",
      "fc2.weight\tparamerters num: 1280\n",
      "fc2.bias\tparamerters num: 10\n"
     ]
    }
   ],
   "execution_count": 51
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:52.365009Z",
     "start_time": "2025-02-09T09:17:52.312972Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def count_parameters(model):  #计算模型总参数量\n",
    "    return sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
    "\n",
    "\n",
    "count_parameters(CNN())"
   ],
   "id": "dec3cf8e93a746ea",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "9725610"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 52
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 模型训练",
   "id": "fb1ef356be54dce7"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:52.700050Z",
     "start_time": "2025-02-09T09:17:52.696751Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)  # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "\n",
    "        preds = logits.argmax(axis=-1)  # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "\n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "id": "f181d3bd58308549",
   "outputs": [],
   "execution_count": 53
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:52.892949Z",
     "start_time": "2025-02-09T09:17:52.888444Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "\n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\",\n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "\n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "\n",
    "        )\n",
    "\n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "id": "f3ed89508e560534",
   "outputs": [],
   "execution_count": 54
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:53.084049Z",
     "start_time": "2025-02-09T09:17:53.079538Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "\n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "id": "2999b1b143403dad",
   "outputs": [],
   "execution_count": 55
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:53.310707Z",
     "start_time": "2025-02-09T09:17:53.306436Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else:\n",
    "            self.counter += 1\n",
    "\n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "id": "96b938cbe2dbaafe",
   "outputs": [],
   "execution_count": 56
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:17:53.773640Z",
     "start_time": "2025-02-09T09:17:53.507221Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 训练\n",
    "def training(\n",
    "        model,\n",
    "        train_loader,\n",
    "        val_loader,\n",
    "        epoch,\n",
    "        loss_fct,\n",
    "        optimizer,\n",
    "        tensorboard_callback=None,\n",
    "        save_ckpt_callback=None,\n",
    "        early_stop_callback=None,\n",
    "        eval_step=500,\n",
    "):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "\n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "\n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step,\n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                        )\n",
    "\n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "\n",
    "    return record_dict\n",
    "\n",
    "\n",
    "epoch = 20\n",
    "\n",
    "activation = \"relu\"\n",
    "model = CNN(num_classes=10, activation=activation)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001, eps=1e-7)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(f\"runs/monkeys-cnn-{activation}\")\n",
    "tensorboard_callback.draw_model(model, [1, 3, img_h, img_w])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(f\"checkpoints/monkeys-cnn-{activation}\", save_step=len(train_loader),\n",
    "                                             save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)"
   ],
   "id": "d6f76295b30bf083",
   "outputs": [],
   "execution_count": 57
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:33:28.613460Z",
     "start_time": "2025-02-09T09:17:53.834988Z"
    }
   },
   "cell_type": "code",
   "source": [
    "model = model.to(device)\n",
    "record = training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    val_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_loader)\n",
    ")"
   ],
   "id": "59c197f7e48b0ae3",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/360 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "e2213c48dcba4e63858a4b5848aba7c5"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 18 / global_step 324\n"
     ]
    }
   ],
   "execution_count": 58
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:33:29.161469Z",
     "start_time": "2025-02-09T09:33:28.617474Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):\n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ],
   "id": "6e7d7b42261a772b",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 59
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 评估",
   "id": "26c7f1c1af1a6a1"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-09T09:33:41.474763Z",
     "start_time": "2025-02-09T09:33:29.165528Z"
    }
   },
   "cell_type": "code",
   "source": [
    "model.load_state_dict(torch.load(f\"checkpoints/monkeys-cnn-{activation}/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, val_loader, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "id": "e25314f2456f2a2",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     3.0394\n",
      "accuracy: 0.5993\n"
     ]
    }
   ],
   "execution_count": 60
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "17538c94b840c8c1"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
